跳到主要内容

与不透明数据类型一起使用

不透明数据类型是您定义扩展数据库服务器的原子数据类型。数据库服务器不具有有关不透明数据类型的信息,直到您提供描述它的例程。

扩展数据库服务器频繁需要您创建用户定义的例程(UDR)来支持此扩展。UDR 是您创建的例程,可以在 SQL 语句,数据库服务器或其他 UDR 中调用。UDR 可以是不透明数据类型的一部分,也可以是单独的。

JDBC 3.0 标准提供 java.sql.SQLInput 和 java.sql.SQLOutput 方法访问不透明数据类型。这些接口的定义扩展为完全支持 GBase 8s 固定二进制和可变二进制不透明数据类型。此扩展包括以下接口:

  • IfmxUdtSQLInput
  • IfmxUdtSQLOutput

此外,以下类同样从 JDBC 客户端应用程序在数据库服务器中创建 Java™ 不透明类型和 UDR :

  • UDTManager
  • UDTMetaData
  • UDRManager
  • UDRMetaData

UDTManager 和 UDRManager 类提供将客户端 Java 类映射为不透明数据类型和 UDR,并将它们的实例存储在数据库中的基础架构。

此工具只能在客户端 JDBC 中使用。有关服务器端 JDBC 的功能和限制,请参阅 J/Foundation 开发者指南。

有关不透明数据类型和 UDR 的详细信息,请参阅以下手册:

  • GBase 8s 用户定义的例程和数据类型开发者指南 描述了有关不透明类型和 UDR 的术语和概念,包括内部数据结构,支持的功能以及隐式和显式强制转换,这些是您需要在本节中使用的信息。
  • J/Foundation 开发者指南 描述了在 Java 中编写 UDR 的具体信息。

IfmxUDTSQLInput 接口

com.gbasedbt.jdbc.IfmxUdtSQLInput 接口使用一些添加的方法扩展 java.sql.SQLInput。要使用这些方法,必须将 SQLInput 强制转型为IfmxUdtSQLInput。此方法允许您执行以下功能:

  • 读取数据。
  • 于数据流中定位。
  • 设置或获取数据的数据。

读取数据

readString() 方法读取数据流中下一个属性作为 Java™ 字符串。readBytes() 读取数据流中下一个属性作为 Java 字节组。这两种方法类似于SQLInput.readBytes() 方法,只是读入的是固定长度的数据:

public String readString(int maxlen) throws SQLException;
public byte[] readBytes(int maxlen) throws SQLException;

在这两种方法中,您必须提供长度,以便 GBase 8s JDBC Driver 可以适当地读取下一个属性,因为驱动程序不知道不透明数据类型的特征。maxlen参数指定读入数据的最大长度。

于数据流中定位

getCurrentPosition() 方法检索输入流中的当前位置。setCurrentPosition() 方法将输入流中的位置更改为 position 参数指定的位置:

public int getCurrentPosition();
public void setCurrentPosition(int position) throws SQLException;
public void skipBytes(int len) throws SQLException;

position 参数必须是正整数。skipBytes() 方法根据 len 参数指定相对于当前位置的字节数更改输入流中位置。len 参数必须是正整数。

setCurrentPosition() 和 skipBytes() 中,如果在输入流的末尾之后指定新位置,则 GBase 8s JDBC Driver 生成 SQLException。

设置或获取数据属性

length()方法返回整个数据流的总长度。getAutoAlignment() 方法检索自动对齐功能的状态 TRUE 或 FALSE(on 或 off)。setAutoAlignment() 方法设置状态为 TRUE 或 FALSE:

public int length();
public boolean getAutoAlignment();
public void setAutoAlignment(boolean value);
重要

如果数据尚未对齐,则设置此自动对齐功能可能导致输入流的字节丢失。JDBC 应用程序会提供已对齐的数据或将对齐功能设置为 FALSE。

IfmxUDTSQLOutput 接口

com.gbasedbt.jdbc.IfmxUdtSQLOutput 接口使用以下添加的方法扩展 java.sql.SQLOutput:

public void writeString(String str, int length) throws
SQLException;
public void writeBytes(byte[] b, int length) throws SQLException;

要使用这些方法,必须将 SQLOutput 强制转型为 IfmxUdtSQLOutput。

使用 writeString() 方法将下一个属性作为一个 Java™ 字符串写入数据流。如果传递的字符串长度小于指定的长度,则 GBase 8s JDBC Driver 使用零补齐此字符串。

使用 writeBytes() 方法将下一个属性作为一个 Java 字节组写入数据流。

这些方法类似于 SQLOutput.writeBytes() 方法,除了写入数据流的数据是固定长度的。如果传递的字符串或数组的长度小于指定的长度,则 GBase 8s JDBC Driver 使用零补齐字符串或数组。在这些方法中,您必须为 GBase 8s JDBC Driver 提供长度,以便写入下一个属性,因为对于驱动程序而言不透明数据类型是未知的。

映射不透明数据类型

要将 GBase 8s 不透明类型映射到 Java™ 对象,该对象必须实现 java.sql.SQLData 接口。这些 Java 对象描述构成不透明类型的所有数据成员。它们是强类型;即 Java 对象的 readSQL 或 writeSQL 方法中的每个读取或写入方法都必须与不透明类型定义中相应的数据成员相匹配,因为类型结构是未知的。

GBase 8s JDBC Driver 还要求将所有不透明数据作为 mitypes.h (此文件包含在所有的 GBase 8s 安装中)中定义的 GBase 8s DataBlade API 数据类型。所有的不透明类型都存储在数据库服务器的 C 结构中,该结构由不透明类型中定义的各种 DataBlade API 组成。

如果您使用 UDT 和 UDR Manager 工具创建不透明类型,则需要处理 Java 和 C 之间的映射。有关更多信息,请参阅 创建不透明类型和 UDR。

键入高速缓存信息

当某些数据类型的对象将数据插入某些其它数据类型的列时,GBase 8s JDBC Driver 会验证提供的数据是否与数据库服务器通过调用SQLData.getSQLTypeName() 方法期望的数据匹配。驱动程序向数据库服务器询问每次插入的类型信息。

在以下情况中会发生这种情况:

  • 当一个 SQLData 对象将数据插入到一个不透明类型的列中时,getSQLTypeName() 返回不透明类型的名称
  • 当 Struct 或 SQLData 对象向行列插入数据时,getSQLTypeName() 返回已命名行的名称
  • 当一个 SQLData 对象将数据插入到 DISTINCT 类型列中时

在数据库 URL 中,可以设置环境变量 ENABLE_TYPE_CACHE=TRUE,以使驱动程序在首次检索数据类型信息时缓存该数据类型信息。在向数据库服务器请求数据之前,驱动程序会向缓存询问类型信息。

不支持的方法

不透明类型不支持下列 SQLInput 和 SQLOutput 方法:

  • java.sql.SQLInput
    • readAsciiStream()
    • readBinaryStream()
    • readBytes()
    • readCharacterStream()
    • readObject()
    • readRef()
    • readString()
  • java.sql.SQLOutput
    • writeAsciiStream(InputStream x)
    • writeBinaryStream(InputStream x)
    • writeBytes(byte[] x)
    • writeCharacterStream(Reader x)
    • writeObject(Object x)
    • writeRef(Ref x)
    • writeString(String x)

创建不透明类型和 UDR

UDTManager 和 UDRManager 类可以使您更加容易地在数据库服务器中创建和部署不透明类型和用户定义的例程(UDR)。

在使用本节中信息之前,请阅读以下两个手册:

  • 有关配置您的系统支持 Java™ UDR 的信息,请参阅 J/Foundation 开发者指南。
  • 有关开发不透明类型的详细信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 。

创建不透明类型和 UDR 概述

在数据库服务器中,任何实现 java.sql.SQLData 接口并可以被 Java™ Virtual Machine 访问的 Java 类都可以存储为不透明类型。UDTManager和 UDRManager 类与它们支持的 UDTMetaData 和 UDRMetaData 类一起使用,将此功能扩展到您的客户端应用程序:您的 Java 客户端应用程序可以使用这些类创建不透明类型和用户定义的例程,并将它们的类定义传送到数据库服务器。客户端不需要访问到数据库服务器来使用此功能。

重要: 此功能与服务器支持密切配合,可以创建和使用 Java 不透明类型和用户定义例程。数据库服务器版本中存在的 Java 不透明类型和用户定义例程的任何限制同样适用于您在客户端应用程序中创建 Java 不透明类型和例程。

当使用 UDTManager 和 UDTMetaData 类时,GBase 8s JDBC Driver 为您的应用程序执行以下操作:

  1. 获取您指定的 JAR 文件

  2. 将此 JAR 文件从客户端本地区域传输到服务器本地区域

    使用 UDTManager.setJarFileTmpPath() 方法定义服务器本地区域。在 UNIX™ 系统上默认为 /tmp,在 Windows™ 系统上默认为C:\temp 。

  3. 在服务器中安装此 JAR 文件

  4. 使用 CREATE OPAQUE TYPE SQL 语句在数据库中注册不透明数据类型,从 UDTMetaData 类获取输入

  5. 注册支持函数并使用 CREATE 函数和 CREATE CAST SQL 语句强制转换为不透明类型

    可以使用 UDTMetaData 类中的 setSupportUDR() 和 setXXXCast() 方法定义支持的函数。

    如果您未为不透明类型提供输入和输出函数,则驱动程序注册缺省的函数(有关此功能的任何限制,请参阅发行说明)。

  6. 注册您指定的任何其他不支持的例程或强制转换(如果有的话),从应用程序中的 UDTMetaData.setUDR() 和UDTMetaData.setXXXCast() 方法调用中获取输入

  7. 在 SQL OPAQUE 类型和 Java 对象中创建映射(使用 sqlj.setUDTExtName() 方法)

当使用 UDRManager 和 UDRMetaData 类时,GBase 8s JDBC Driver 执行以下操作:

  1. 获取您指定的 JAR 文件
  2. 将此 JAR 文件从客户端本地区域传输到服务器本地区域
  3. 在服务器中安装此 JAR 文件
  4. 使用 CREATE FUNCTION TYPE SQL 语句在数据库中注册不透明数据类型,在您的应用程序获取 UDRMetaData.setUDR() 方法调用的输入

UDT 和 UDR Manager 工具中的方法执行以下主要功能:

  • 使用服务器提供的缺省输入和输出方法,在 Java 类不存在的情况下,在 Java 中创建不透明类型
  • 将客户端上现有的 Java 类转换为数据库服务器中不透明类型和 UDR
  • 将 Java 静态方法转换为 UDR

准备创建不透明类型和 UDR

在使用 UDT 和 UDR Manager 工具之前,请按照以下步骤执行任务:

  • 请确保您的数据库服务器支持 Java™。

UDT 和 UDR Manager 工具在不支持 Java 的服务器上无法运行。

  • 您的 CLASSPATH 设置中包含 gbasedbtjdbc_xx.jar 文件。
  • 在数据库服务器中创建名为 /usr/gbasedbt 的目录,将它的所有者和组设置为用户 gbasedbt,将权限设置为 777。
  • 将以下条目添加到数据库服务器的 /etc/group 文件中。
gbasedbt::unique-id-number:
  • 检查驱动程序和数据库服务器的发版说明,以获取此版本中的进一步的限制。

创建不透明类型

使用 UDT Manager,可以从实现 SQLData 接口的现有 Java™ 类创建 Java 不透明类型。UDT Manager 还可以帮助您在不需要准备 Java 类的情况下,创建 Java 不透明类型,可以指定要创建的不透明类型的特征, UDT Manager 工具创建 Java 类然后创建 Java 不透明类型。

按照本节中的步骤使用 UDTManager 类。

从现有 Java 类创建不透明类型

从现有 Java™ 类创建不透明类型:

  1. 确保类符合转换为不透明类型的要求。

    有关要求,请参阅Java 类的要求。

  2. 如果您不想使用服务器提供的缺省输入和输出例程,请编写支持的 UDR 以进行输入和输出。

    有关编写支持的 UDR 的一般信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 。

  3. 在数据库服务器上创建一个缺省 sbspace 来保存包含不透明类型代码的 JAR 文件。

    有关创建 sbspace 的信息,请参阅您的数据库服务器的《GBase 8s 管理员指南》和 J/Foundation 开发者指南。

  4. 打开一个 JDBC 连接。

    确保数据库对象与连接对象相关联。没有数据库对象,驱动程序就无法创建不透明类型。有关创建具有数据库对象的连接的详细信息,请参阅连接至数据库。

  5. 安装 UDTManager 对象和 UDTMetaData 对象:

    UDTManager udtmgr = new UDTManager(connection);
    UDTMetaData mdata = new UDTMetaData();
  6. 通过调用 UDTMetaData 对象中的方法设置不透明类型的属性。

    至少,您必须指定 SQL 名称、UDT 长度和 JAR 文件 SQL 名称。有关 SQL 名称的解释,请参阅 SQL 名称。

    还可以指定对齐方式、隐式和显式强制转换以及任何支持的 UDR:

    mdata.setSQLName("circle2");
    mdata.setLength(24);
    mdata.setAlignment(UDTMetaData.EIGHT_BYTE)
    mdata.setJarFileSQLName("circle2_jar");
    mdata.setUDR(areamethod, "area");
    mdata.setSupportUDR(input, "input", UDTMetaData.INPUT)
    mdata.setSupportUDR(output, "output",UDTMetaData.OUTPUT)
    mdata.SetImplicitCast(com.gbasedbt.lang.IfxTypes.IFX_TYPE_
    LVARCHAR, "input");
    mdata.SetExplicitCast(com.gbasedbt.lang.IfxTypes.IFX_TYPE_
    LVARCHAR, "output");
  7. 如果需要,请指定驱动程序应将 JAR 文件放在数据库服务器文件系统中的路径名称:

    String pathname = "/work/srv93/examples";udtmgr.setJarFileTmpPath(pathname);

    请确保服务器文件系统中存在此路径。有关更多信息,请参阅指定 JAR 文件临时路径。

  8. 创建不透明类型:

    udtmgr.createUDT(mdata, "Circle2.jar", "Circle2", 0);

有关从现有代码创建不透明类型的其它信息,请参阅从现有代码创建不透明类型。

有关使用上述步骤创建不透明类型的完整代码示例,请参阅使用 UDTManager 从现有的 Java 类创建不透明类型。

创建不透明类型,无需现有 Java 类

无需现有 Java™ 类创建不透明类型:

  1. 在数据库服务器上创建一个缺省 sbspace 来保存包含不透明类型代码的 JAR 文件。

    有关创建 sbspace 的信息,请参阅您的数据库服务器的《GBase 8s 管理员指南》和 J/Foundation 开发者指南。

  2. 打开一个 JDBC 连接。

    确保数据库对象与连接对象相关联。有关创建具有数据库对象的连接的详细信息,请参阅连接至数据库。

  3. 安装 UDTManager 对象和 UDTMetaData 对象:

    UDTManager udtmgr = new UDTManager(connection);
    UDTMetaData mdata = new UDTMetaData();
  4. 通过调用 UDTMetaData 对象中的方法设置不透明类型的属性:

    mdata.setSQLName("acircle");
    mdata.setLength(24);
    mdata.setFieldCount(3);
    mdata.setFieldName(1, "x");
    mdata.setFieldName(2, "y");
    mdata.setFieldName(3, "radius");
    mdata.setFieldType
    (1,com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT);
    mdata.setFieldType
    (2,com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT);
    mdata.setFieldType
    (3,com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT);
    mdata.setJarFileSQLName("ACircleJar");

    有关不透明类型的设置属性的更多信息,请参 指定不透明类型的属性

  5. 创建 Java 文件、类文件和 JAR 文件:

    mdata.keepJavaFile(true);
    String classname = udtmgr.createUDTClass(mdata);
    String jarfilename = udtmgr.createJar(mdata, new String[] {classname + .class"});

    有关更多信息,请参阅创建 JAR 和类文件。

  6. 如果需要,请指定驱动程序应将 JAR 文件放在数据库服务器文件系统中的路径名称:

    String pathname = "/work/srv93/examples";udtmgr.setJarFileTmpPath(pathname);

    请确保此路径在服务器文件系统中存在。有关更多信息,请参阅指定 JAR 文件临时路径。

  7. 将类定义发送到数据库服务器:

    udtmgr.createUDT(mdata, jarfilename, classname, 0);

    有关更多信息,请参阅将类定义发送到数据库服务器。

有关使用上述步骤创建不透明类型的完整代码示例,请参阅不需现有的 Java 类创建不透明类型。

创建 UDR

以下主题显示如何从 Java™ 类创建 UDR。

创建 UDR:

  1. 编写要注册为 UDR 的具有一个或多个静态方法的 Java 类。

    有关更多信息,请参阅Java 类的要求。

  2. 在数据库服务器上创建一个 sbspace 保存包含此 UDR 代码的 JAR 文件。

    有关创建 sbspace 的更多信息,请参阅您的数据库服务器的 GBase 8s 管理员指南和 J/Foundation 开发者指南。

  3. 打开一个 JDBC 连接。

    请确保连接对象具有与其相关联的数据库对象。有关详细信息,请参阅连接至数据库。

  4. 安装 UDRManager 对象和 UDRMetaData 对象:

    UDRManager udrmgr = new UDRManager(myConn);
    UDRMetaData mdata = new UDRMetaData();
  5. 创建 java.lang.Reflect.Method 对象,以便静态方法可注册为 UDR。

    在以下示例中,method1 是代表 Group1 Java 类的 udr1(string, string) 方法的实例;method2 是代表 Group1 Java 类的 udr2(Integer, String, String)方法的实例:

    Class gp1 = Class.forName("Group1");
    Method method1 = gp1.getMethod("udr1",
    new Class[]{String.class, String.class});
    Method method2 = gp1.getMethod("udr2",
    new Class[]{Integer.class, String.class, String.class});
  6. 指定要注册为 UDR 的方法。

    第二个参数指定 UDR 的 SQL 名称:

    mdata.setUDR(method1, "group1_udr1");
    mdata.setUDR(method2, "group1_udr2");

    有关更多信息,请参阅创建 UDR。

  7. 指定 JAR 文件 SQL 名:

    mdata.setJarFileSQLName("group1_jar");
  8. 如果需要,请指定驱动程序应将 JAR 文件放在数据库服务器文件系统中的路径名称:

    String pathname = "/work/srv93/examples"; udrmgr.setJarFileTmpPath(pathname);

    请确保数据服务器文件系统中存在此路径。有关更多信息,请参阅指定 JAR 文件临时路径。

  9. 在数据库服务器中安装 UDR:

    udrmgr.createUDRs(mdata, "Group1.jar", "Group1", 0);

    有关更多信息,请参阅创建 UDR。

有关创建 UDR 的完整示例代码,请参阅使用 UDRManager 创建 UDR。

Java 类的要求

要转换为不透明类型,Java™ 类必须满足以下条件:

  • 类必须实现 java.sql.SQLData 接口。有关示例,请参阅示例。

  • 如果类包含其它不透明类型,则必须以类似的方式实现附加的不透明类型,并且必须将附加的 .class 文件打包为与原始不透明类型相同的 JAR 文件的一部分。

  • 如果类包含 DISTINCT 类型,则该类可以为 DISTINCT 类型实现 SQLData 接口,或者让驱动程序将 DISTINCT 类型映射到基础类型。有关更多信息,请参阅distinct 数据类型。

  • 该类不能包含复杂类型。

  • 如果您从现有的 Java 类创建不透明类型,并在数据库服务器中使用缺省支持的函数,则必须将 SQLData.readSQL() 和SQLData.writeSQL() 中的 SQLInput 和 SQLOutput 流强制转换为 IfmxUDTSQLInput 和 IfmxUDTSQLOutput。

    有关如何执行此操作的示例代码,请参阅使用缺省的支持函数创建不透明类型。

  • 所有不透明类型的 Java 方法必须与定义不透明类型的类在相同的 .java 文件中。

UDR 的其它要求如下所示:

  • 所有注册为 UDR 的类方法必须是静态的。
  • 方法参数类型和返回类型必须是有效的 Java 数据类型。
  • 这些方法可以使用 JDK 中包含的所有基本的非图形类 Java 包,例如 java.util 、java.io 、java.net 、java.rmi 、java.sql 等等。
  • 方法参数和返回类型的数据类型必须符合UDT manager 和 UDR manager 的数据类型映射中显示的数据类型映射表。
  • 不支持以下 SQL 参数或返回类型:
    • MONEY
    • 具有除 hour to second 或 year to fraction(5) 之外的限定符的 DATETIME
    • 具有除 year to month 或 day to fraction(5) 之外限定符的 INTERVAL
    • 不在方法参数和返回类型的映射表中显示的任何数据类型;对于这些表,请参阅UDT manager 和 UDR manager 的数据类型映射。

SQL 名称

UDTMetaData 类中的某些方法为不透明类型或包含不透明类型或 UDR 代码的 JAR 文件设置 SQL 名称。 SQL 名称是在 SQL 语句中引用的对象的名称。例如,假设您的应用程序发出以下调用:

mdata.setSQLName("circle2");

SQL 语句中使用的名称如下所示:

CREATE TABLE tab (c circle2);

同样,假定应用程序将 JAR 文件名设置如下所示:

mdata.setJarFileSQLname("circle2_jar");

按照以下方式在 SQL 中引用 JAR 文件名称:

CREATE FUNCTION circle2_output (...)
RETURNS circle2
EXTERNAL NAME
'circle2_jar: circle2.fromString (...)'
LANGUAGE JAVA
NOT VARIANT
END FUNCTION;
重要

SQL 名称没有缺省值。请使用 setSQLname() 或 setJarFileSQLName() 方法指定名称,否则会抛出一个 SQL 异常。

指定不透明类型的属性

下列主题提供在 Java™ 类不存在时有关创建不透明类型的附加信息。有关从现有 Java 类创建不透明类型的详细信息,请参阅 从现有代码创建不透明类型。

使用 UDTMetaData 类中的方法,可以为新的不透明类型指定属性。这些设置适用于新的不透明类型;从现有文件创建不透明类型,请参阅从现有代码创建不透明类型.。

可以设置以下属性:

  • 内部结构中定义不透明类型的字段数
  • 其它属性,例如内部结构中定义不透明类型的每个字段的数据类型、名称和精度
  • 不透明类型的长度
  • 不透明类型的对齐方式
  • 不透明类型和 JAR 文件的 SQL 名称
  • 已生成的 Java 类的名称
  • 是否保留生成的 .java 文件

指定字段计数

setFieldCount() 方法指定内部结构中定义不透明类型的字段计数:

public void setFieldCount(int fieldCount) throws SQLException

指定其它字段属性

以下方法设置内部数据结构中的字段的其它属性:

public void setFieldName (int field, String name) throws SQLException
public void setFieldType (int field, int ifxtype) throws SQLException
public void setFieldTypeName(int field, String sqltypename) throws SQLException
public void setFieldLength(int field, int length) throws SQLException

field 参数指示驱动程序应设置或获取属性的字段。第一个字段为 1;第二个字段为 2,依次类推。

使用 setFieldName() 指定的名称出现在 Java™ 类文件中。以下示例将第一个字段名称设置为 IMAGE。

mdata.setFieldName(1, "IMAGE");

setFieldType() 方法指示使用 com.gbasedbt.lang.IfxTypes 文件中的常量设置字段的数据类型。有关更多信息,请参阅映射字段类型。以下示例指定第三个字段中的值为 CHAR 数据类型:

mdata.setFieldType(3, com.gbasedbt.lang.IfxTypes.IFX_TYPE_CHAR);

setFieldTypeName() 方法设置使用 SQL 数据类型名称的字段的数据类型:

mdata.setFieldTypeName(1, "IMAGE_UDT");

此方法仅对 opaque 和 distinct 类型有效;对于其它类型,驱动程序会忽略此信息。

length 参数具有以下含义,它取决于字段的数据类型:

字符类型

字符中的最大长度

DATETIME

编码的长度

INTERVAL

编码的长度

其它数据类型或不指定类型

驱动程序忽略此信息

编码长度的可能值为 JDBC 2.20 规范中的值:小时到秒;一年到两年;年份(1),年份(2)到年份(5)。

以下示例指定不透明类型中的第三个字段(VARCHAR)不能存储多于 24 个字符:

mdata.setFieldLength(3, 24);

指定长度

setLength() 方法指定不透明类型的总长度:

public void setLength(int length) throws SQLException

如果您正在从现有的 Java™ 类创建不透明类型并不指定长度,则驱动程序创建可变长度的不透明类型。如果您从不具有现有的 Java 类创建不透明类型,则必须指定长度;在此情况下,UDT Manager 只创建固定长度的不透明类型。

指定对齐方式

setAlignment() 方法指定不透明类型的对齐方式:

public void setAlignment(int alignment)

alignment 参数是下一节中显示的对齐值之一。如果未指定对齐方式,则数据库服务器设置不透明类型 4 字节对齐。

对齐值

对齐值如下表所示。

常量结构始于边界对齐
1SINGLE_BYTE1 个字节的数量单个字节
2TWO_BYTE2 个字节的数量(例如 SMALLINT)2 个字节
4FOUR_BYTE4 个字节的数量(例如 FLOAT 或 UNSIGNED INT)4 个字节
8EIGHT_BYTE8 个字节的数量8 个字节

指定 SQL 名称

使用 setSQLName() 和 setJarFileSQLName()方法指定 SQL 名称:

public void setSQLName(String name) throws SQLException
public void setJarFileSQLName(String name) throws SQLException

缺省情况下,驱动程序使用通过 setSQLName() 方法设置的名称作为当调用 UDTManager.createUDTCclass() 和 UDTManager.createJar() 方法时生成的 JAR 文件和 Java™ 类的文件名称。例如,如果调用 setSQLName("circle") 然后调用 createUDTCclass() 和 createJar(),则生成的类文件名将会是 circle.class ,JAR 文件名将会是 circle.jar。可以通过调用 setClassName() 方法指定 Java 类文件名而不是缺省值。

JAR 文件 SQL 名称是驱动程序用于注册 UDR 的 SQL CREATE FUNCTION 语句中引用的名称。

重要

JAR 文件 SQL 名是 SQL 语句中 JAR 文件的名称;它与 JAR 文件的内容没有关系。

指定 Java 类名称

使用 setClassName() 指定 Java™ 类名称:

public void setClassName(String name)throws SQLException

如果未使用 setClassName() 设置类名称,则驱动程序使用不透明类型的 SQL 名称(通过 setSQLName() 设置)和 createUDTCclass() 方法生成的.class 文件的名称作为 Java™ 类的名称。

指定 Java 源文件保留

使用 keepJavaFile() 指定是否保留 .java 源文件:

public void keepJavaFile(boolean value)

value 值指示 createUDTClass() 方法是否应该保留它在为新的不透明类型创建 Java™ 类文件时生成的 .java 文件。缺省为移除此文件。以下示例保留 .java 文件:

mdata.keepJavaFile(true);

创建 JAR 和类文件

一旦您使用 UDTMetaData 方法指定了不透明类型的属性,您可以按照以下顺序使用类中的方法创建不透明类型及其类和 JAR 文件:

  1. 实例化 UDTManager 对象。

    如以下所示建立连接:

    public UDTManager(Connection conn) throws SQLException
  2. 使用 createUDTClass() 方法创建 .class 和 .java 文件。

  3. 使用 createJar() 方法创建 .jar 文件。

  4. 使用 createUDT() 方法创建不透明类型。

创建 .class 和 .java 文件

createUDTClass() 方法具有以下签名:

public String createUDTClass(UDTMetaData mdata) throws SQLException

createUDTClass() 方法导致驱动程序为应用程序执行所有以下操作:

  1. 使用 UDTMetaData.setClassName() 方法中指定的名称创建一个 Java™ 类

    如果未指定类名称,则驱动程序使用 UDTMetaData.setSQLName() 方法中指定的名称。

  2. 将 Java 类代码放到 .java 文件中,然后编译此文件为 .class 文件。

  3. 将新创建的名称返回到应用程序。

如果通过调用 UDTMetaData.keepJavaFile() 方法指定 TRUE,则驱动程序保留生成的 .java 文件。缺省操作为删除此 .java 文件。

应用程序调用 createUDTClass() 方法仅创建定义不透明类型的新 .class 和 .java 文件,而不从现有文件生成不透明类型。

创建 .jar 文件

createJar() 方法编译您在 classnames 列表中指定的类。列表中的文件必须具有 .class 扩展名。

public String createJar(UDTMetaData mdata, String[] classnames)
throws SQLException;

驱动程序创建名为 sqlname.jar 的 JAR 文件(其中 sqlname 是您通过调用 UDTMetaData.setSQLName() 指定的名称 )并将文件名返回到应用程序。

将类定义发送到数据库服务器

创建 JAR 文件之后,使用 UDTManager.createUDT() 方法通过将类定义发送到数据库服务器来创建不透明类型:

public void createUDT(UDTMetaData mdata, String jarfile, String
classname, int deploy) throws SQLException;

jarfile 参数是包含不透明类型的类定义的 JAR(.jar)文件的路径名。缺省情况下,java.io 包中的类编译相对路径名而不是系统属性 user.dir 命名的当前用户目录;它通常是 Java™ Virtual Machine 调用的目录。如果您使用绝对路径名,则文件名称必须包含在您的 CLASSPATH 设置中。

classname 参数是实现不透明类型的类的名称。

如果应用程序没有调用 setClassName(),则类名称使用缺省的不透明类型的 SQL 名称。您可以通过调用 UDTMetaData.setSQLName() 方法指定 SQL 名称。

重要

如果应用程序在事务中调用 createUDT() 或者数据库是 ANSI 或启用日志记录,则会应用一些扩展的规则。有关更多信息,请参阅在事务中执行。

指定部署描述符操作

UDTManager 和 UDRManager方法中,deploy 参数指示在 JAR 文件中存在部署描述符时 install_actions 是否执行。undeploy 参数指示是否执行 remove_actions。

0

执行 install_actions 或 remove_actions。

非零

不执行 install_actions 或 remove_actions。

部署描述符允许您包含用于在 JAR 文件中创建和删除 UDR 的 SQL 语句。有关部署描述符的更多信息,请参阅 J/Foundation 开发者指南 和 SQLJ 规范。

指定 JAR 文件临时路径

当驱动程序为不透明类型或 UDR 发送 JAR 文件时,它将文件缺省放在 /tmp(UNIX™ 上)或 C:\temp(Windows™ 上)。可以通过调用UDTManager 或 UDRManager 类中的 setJarTmpPath() 方法,指定替代路径:

public void setJarTmpPath(String path) throws SQLException

您可以在调用 createUDT() 或 createUDR()、UDTManager 或 UDRManager 对象之前,随时调用此方法。path 参数必须是绝对路径名。您必须确保路径在服务器文件系统上存在。

从现有代码创建不透明类型

前面的主题描述了用于创建不包含现有 Java™ 类的新的不透明类型的方法。从现有 Java 代码创建不透明类型时,请指定不透明类型中包含的 SQL 名称、JAR 文件 SQL 名称、支持的 UDR(如果有)和任何其他不支持的 UDR。(有关 SQL 名称的解释,请参阅SQL 名称。)还可以指定长度、对齐方式、隐式和显式强制转换。

要从现有的代码创建不透明类型。请使用以下方法:

  • UDTMetaData.setSQLName() 指定 SQL 语句中引用的不透明类型的 SQL 名称
  • 对于不透明类型中支持的 UDR 使用 UDTMetaData.setSupportUDR()

支持的 UDR 为输入/输出、发送/接收等等。

  • 对于不透明类型中不支持的 UDR 使用 UDTMetaData.setUDR()
  • UDTMetaData.setJarFileSQLName() 指定 JAR 文件的 SQL 名称
  • UDTMetaData.setImplicitCast() 或 UDTMetaData.setExplicitCast() 指定强制转换
  • 如果不透明类型是固定长度的,使用 UDTMetaData.setLength() (驱动程序缺省为可变长度)
  • UDTMetaData.setAlignment() 指定不透明类型所对齐的字节边界(仅当您不希望数据库服务器默认 4 字节边界时)
  • UDTManager.createJar() 创建 JAR(.jar)文件(如果没有)
  • UDTManager.createUDT() 创建不透明类型

另外,setXXXCast() 、setSupportUDR() 和 setUDR() 方法仅用于从现有代码创建不透明类型:

public void setImplicitCast(int ifxtype, String methodsqlname)
throws SQLException
public void setExplicitCast(int ifxtype, String methodsqlname)
throws SQLException
public void setSupportUDR(Method method, String sqlname, int type)
throws SQLException
public void setUDR(Method method, String sqlname)
throws SQLException

setXXXCast() 方法

setXXXCast() 方法指定显式或隐式将不透明类型转换为指定的数据类型。

ifxtype 参数是类 com.gbasedbt.lang.IfxTypes 的类型代码。数据库服务器中的 ifxtype 参数和 SQL 类型之间的数据类型映射在映射转换类型中进行了详细说明。methodsqlname 参数是实现此转换的 Java™ 方法的 SQL 名称。

以下示例使用 SQL 名称 circle2_input 设置由 Java 方法实现的隐式转换:

setImplicitCast(com.gbasedbt.lang.IfxTypes.IFX_TYPE_LVARCHAR, "circle2_input");

以下示例使用 SQL 名称 circle_output 设置由 Java 方法实现的显式转换:

setExplicitCast(com.gbasedbt.lang.IfxTypes.IFX_TYPE_LVARCHAR, "circle2_output");

以下示例设置一个显式转换,将 circle2 不透明类型转换为整数:

setExplicitCast(com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT, "circle2_to_int");

setSupportUDR() 和 setUDR() 方法

setSupportUDR() 方法在现有 Java™ 类中指定 Java 方法,该类将被注册为不透明类型支持的 UDR。

method 参数指定 java.lang.reflect.Method 中的一个对象,将其注册为数据库服务中不透明类型的 Java 支持 UDR。支持的 UDR 为输入、输出、发送、接收等等。(有关更多信息,请参阅 GBase 8s 用户定义的例程和数据类型开发者指南 。)

sqlname 参数指定方法的 SQL 名。有关更多信息,请参阅 SQL 名称。

type 参数指定支持的 UDR 的类型。如下所示:

UDTMetaData.INPUT
UDTMetaData.OUTPUT
UDTMetaData.SEND
UDTMetaData.RECEIVE
UDTMetaData.IMPORT
UDTMetaData.EXPORT
UDTMetaData.BINARYIMPORT
UDTMetaData.BINARYEXPORT

有关如何从现有代码创建不透明类型的操作步骤,请参阅从现有 Java 类创建不透明类型。

提示

不必注册 SQLData 接口中方法。例如,您不需注册 SQLData.getSQLTypeName() 、SQLData.readSQL() 或 SQLData.writeSQL()。

要指定其他 UDR,使用创建 UDR 中描述的 setUDR()。

移除不透明类型和 JAR 文件

可以使用以下方法移除不透明类型及其 JAR 文件:

public static void removeUDT(String sqlname) throws SQLException
public static void removeJar(String jarfilesqlname, int undeploy)
throws SQLException

removeUDT() 方法从数据库服务器移除不透明类型,以及所有它的强制转型和 UDR 。它不会移除 JAR 文件本身,因为其它不透明类型或 UDR 可能正在使用相同的 JAR 文件。

重要

如果应用程序在事务中调用 removeUDT() 或您的数据库是 ANSI 或启用了日志记录,则要应用一些其它规则。有关更多信息,请参阅在事务中执行。

removeJar() 方法从系统目录移除 JAR 文件。jarfilesqlname 参数是使用 setJarFileSQLName() 方法指定的名称。

对于 undeploy 参数,请参阅指定部署描述符操作。

重要

在调用 removeJar() 之前,您必须首先移除所有与 JAR 文件关联的函数和过程。否则,数据库服务器移除文件失败。

创建 UDR

使用 UDR Manager 在数据库服务器中创建 UDR,包括:

  • 编码 UDR 并将代码打包到 JAR 文件中

    有关编码 UDR 的信息,请参阅 J/Foundation 开发者指南。

  • 在数据库服务器中创建缺省的 sbspace 来保存包含 UDR 代码的 JAR 文件

    有关创建 sbspace 的信息,请参阅您的数据库服务器的《GBase 8s 管理员指南》和 J/Foundation 开发者指南。

  • 调用 UDRMetaData 类中的方法指定 GBase 8s JDBC Driver 在数据库服务器中注册 UDR 所必需的信息

  • 如果需要。请指定驱动程序应将 JAR 文件放在数据库服务器文件系统中的路径名

  • 在服务器中安装 UDR

为 C 语言不透明类型创建的 UDR 是不受支持的;不透明类型必须是 Java™ 的。

要指定注册的驱动程序的 UDR ,请使用 UDRMetaData 中的这个方法:

public void setUDR(Method method, String sqlname) throws SQLException

method 参数指定要在数据库服务器中注册为 Java UDR 的 java.lang.Reflect.Method 中的对象。sqlname 参数是用于 SQL 语句中方法的名称。

一旦您指定了要注册的 UDR,则可以使用 UDRMetaData.setJarFileSQLName() 设置 JAR 文件 SQL 名称,然后使用UDRManager.createUDRs() 方法在数据库服务器中安装此 UDR,如下所示:

public void createUDRs(UDRMetaData mdata, String jarfile, String classname, int deploy) throws SQLException

jarfile 参数是包含 Java 方法定义的客户端 JAR 文件的绝对或相对路径名。如果使用绝对路径名,则 JAR 文件名必须包含在您 CLASSPATH 设置中。

classname 参数是包含您要在数据库服务器中注册为 UDR 的 Java 类的名称。有关准备 Java 方法的要求,在 1 中描述。

对于 deploy 参数,请参阅指定部署描述符操作。

createUDRs() 方法使驱动程序为您的应用程序执行以下所有步骤:

  1. 获取第一个参数指定的 JAR 文件。
  2. 将 JAR 文件从客户端本地区域传送到服务器本地区域。
  3. 注册 UDRMetaData 对象中指定的 UDR(通过调用一个多个 UDRMetaData.setUDR())。
  4. 在服务器上安装 JAR 文件并创建 UDR。

执行 createUDRs() 后,您的应用程序就可以在 SQL 语句中使用 UDR。

重要

如果应用程序在事务中调用 createUDRs(),或者您的数据库为 ANSI 或启用了日志记录,会应用一些其它规则。有关更多信息,请参阅在事务中执行。

移除 UDR 和 JAR 文件

可用使用以下方法移除 UDR:

public void removeUDR(String sqlname) throws SQLException
public void removeJar(String jarfilesqlname, int undeploy) throws
SQLException
提示

removeUDR() 方法从服务器移除 UDR 但是不移除 JAR 文件,因为其它不透明类型或 UDR 会使用相同的 JAR 文件。

removeJar() 方法在移除不透明类型和 JAR 文件中有所描述。

移除重载的 UDRs

要移除重载的 UDR,请使用具有附加参数的 removeUDR() 方法:

public void removeUDR(String sqlname, Class[] methodparams) throws
SQLException

methodparams 参数指定 UDR 中每个参数的数据类型。指定 NULL 指示没有参数。例如,假设一个名为 print() 的 UDR 被重载了两个额外的方法签名。

Java™ 方法签名对应的 SQL 名
void print()print1
void print(String x, String y, int r)print2
void print(int a, int b)print3

移除所有三个 UDR 的代码为:

udrmgr.removeUDR("print1", null );
udrmgr.removeUDR("print2",
new Class[] {String.class, String.class, int.class} );
udrmgr.removeUDR("print3", new Class[] {int.class, int.class} );

获取有关不透明类型和 UDR 的信息

UDTMetaData 和 UDRMetaData 类中的许多 setXXX() 方法具有相应的 getXXX() 方法,用于获取现有不透明类型和 UDR 的特性。

UDTMetaData 类中的 getXXX() 方法

下表总结了 UDTMetaData 类中可用的 getXXX() 方法。对于 field 参数,1 表示内部数据结构中第一个字段,2 是第二个字段,依次类推。有关 SQL 名称的详细信息,请参阅 SQL 名称。

获取的信息方法签名其它信息
内部数据结构中的字段计数public int getFieldCount()如果没有字段,则返回 0
内部数据结构中的字段名称public String getFieldName int field) throws SQLException如果名称不存在,则返回 NULL
内部数据结构中的字段数据类型代码public int getFieldType (int field) throws SQLException数据类型代码来自类 com.gbasedbt.lang.IfxTypes.。如果数据类型不存在,则返回 -1
内部数据结构中字段的数据类型名称public String getFieldTypeName (int field) throws SQLException如果名称不存在,则返回 NULL
对于字符类型:字段中的最大字符数;对于 date-time 或 interval 类型: 编码限定符public int getFieldLength (int field) throws SQLException如果未设置长度,则返回 -1
不透明类型的 SQL 名称public String getSQLName()如果未设置名称,则返回 NULL
JAR 文件的 SQL 名称public String getJarFileSQLName()如果未设置名称,则返回 NULL
不透明类型的 Java™ 类的名称public String getClassName()如果未通过 setClassName() 设置类名,则返回sqlname(缺省值)。如果未通过 setSQLName() 设置 SQL 名称,则返回 NULL
固定长度的不透明类型的长度public int getLength()如果未设置长度,则返回 -1
不透明类型的对齐方式public int getAlignment()如果未设置对齐方式,则返回 -1 有关对齐方式代码,请参阅对齐值。
已通过 setSupportUDR() 指定为支持 UDR 的方法对象组public Method[] getSupportUDRs()有关支持的 UDR 的详细信息,请参阅从现有代码创建不透明类型中 setSupportUDR() 的描述。如果未指定支持 UDR,则返回 NULL
通过 setSupportUDR() 指定为支持 UDR 的 Java 方法的 SQL 名称public String getSupportUDRSQLName (Methodmethod) throws SQLException如果未设置名称,则返回 NULL

UDRMetaData 类中的 getXXX() 方法

要获取有关 UDR 的信息,请使用下表中的方法。

获取的信息方法签名其它信息
指定为不透明类型的 UDR 的java.lang.Method.Reflect 方法组public Method[] getUDRs()调用 UDTMetaData.setUDR() 为不透明类型指定 UDR。如果没有指定 UDR 则返回 NULL。
Java™ 方法的 SQL 名称public String getUDRSQLName(Method method) throws SQLException如果没有为 UDR 方法对象指定 SQL 名称,则返回 NULL

在事务中执行

如果您的数据库是 ANSI 或启用了日志记录,并且应用程序尚未在事务中,则驱动程序执行 SQL 语句在事务中的服务器上创建不透明类型和 UDR。这意味着所有的步骤都会成功,否则都将失败。如果在任何一点创建不透明类型或 UDR 失败,则驱动程序回滚事务并引发 SQLException。

当发出 UDTManager.createUDT() 或 UDRManager.createUDRs() 调用时,如果事务已在应用程序中,则在现有的事务中执行 SQL 语句。这意味着如果驱动程序在创建不透明类型或 UDR 期间返回一个 SQLException,则您的应用程序必须回滚事务以确保数据库的完整性。否则,不透明类型转换的部分或 UDR 可以保留在数据库中。

示例

本节的剩余部分包含创建和使用不透明类型和 UDR 的示例。

前四个示例在 demo/udt-distinct 目录中随 JDBC 驱动程序软件一起发布;最后两个示例在 demo/tools/udtudrmgr 目录下。请参阅每个目录中的README 文件以获取文件的说明。

类定义

以下示例中的 charattrUDT 是 C 不透明类型的类,它必须实现 SQLData 接口:

import java.sql.*;
import com.gbasedbt.jdbc.*;
/*
* C struct of charattr_udt:
*
* typedef struct charattr_type
* {
* char chr1[4+1];
* mi_boolean bold; // mi_boolean (1 byte)
* mi_smallint fontsize; // mi_smallint (2 bytes)
* }
* charattr;
*
* typedef charattr charattr_udt;
*
*/
public class charattrUDT implements SQLData
{
private String sql_type = "charattr_udt";
// an ASCII character/a multibyte character, and is null-terminated.
public String chr1;
// Is the character in boldface?
public boolean bold;
// font size of the character
public short fontsize;

public charattrUDT() { }

public charattrUDT(String chr1, boolean bold, short fontsize)
{
this.chr1 = chr1;
this.bold = bold;
this.fontsize = fontsize;
}

public String getSQLTypeName()
{
return sql_type;
}
// reads a stream of data values and builds a Java object
public void readSQL(SQLInput stream, String type) throws SQLException
{
sql_type = type;
chr1 = ((IfmxUDTSQLInput)stream).readString(5);
bold = stream.readBoolean();
fontsize = stream.readShort();
}
// writes a sequence of values from a Java object to a stream
public void writeSQL(SQLOutput stream) throws SQLException
{
((IfmxUDTSQLOutput)stream).writeString(chr1, 5);
stream.writeBoolean(bold);
stream.writeShort(fontsize);
}
// overides Object.equals()
public boolean equals(Object b)
{
return (chr1.equals(((charattrUDT)b).chr1) &&
bold == ((charattrUDT)b).bold &&
fontsize == ((charattrUDT)b).fontsize);
}

public String toString()
{
return "chr1=" + chr1 + " bold=" + bold + " fontsize=" + fontsize;
}
}

在 JDBC 应用程序中,自定义类型映射必须将 SQL 类型名 charattr_udt 映射到 charattrUDT 类:

java.util.Map customtypemap = conn.getTypeMap();
if (customtypemap == null)
{
System.out.println("\n***ERROR: typemap is null!");
return;
}
customtypemap.put("charattr_udt", Class.forName("charattrUDT"));

插入数据

可以插入不透明类型的原始类型或它的转换类型。以下示例显示如何插入使用原始类型的不透明数据:

String s = "insert into charattr_tab (int_col, charattr_col)
values (?, ?)";
System.out.println(s);
pstmt = conn.prepareStatement(s);
...
charattrUDT charattr = new charattrUDT();
charattr.chr1 = "a";
charattr.bold = true;
charattr.fontsize = (short)1;

pstmt.setInt(1, 1);
System.out.println("setInt...ok");

pstmt.setObject(2, charattr);
System.out.println("setObject(charattrUDT)...ok");

pstmt.executeUpdate();

如果定义了强制转换函数,并且想要将数据作为转换类型而不是原始类型插入,则必须调用与转换类型相对应的 setXXX() 方法。例如,如果已经将 CHAR 或 LVARCHAR 函数转换为 charattrUDT 列,则可以使用 setString() 方法插入数据,如下所示:

// Insert into UDT column using setString(int,String) and Java
String object.
String s =
"insert into charattr_tab " +
"(decimal_col, date_col, charattr_col, float_col) " +
"values (?,?,?,?)";
writeOutputFile(s);
PreparedStatement pstmt = myConn.prepareStatement(s);

...
String strObj = "(A, f, 18)";
pstmt.setString(3, strObj);
...

检索数据

要检索 GBase 8s 不透明类型,必须使用 ResultSet.getObject()。GBase 8s JDBC Driver 根据您提供的自定义类型将数据转换为 Java™ 对象。使用前面示例的 charattrUDT 类型,可以获取此不透明数据,如下所示:

String s = "select int_col, charattr_col from charattr_tab order by 1";
System.out.println(s);

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(s);
System.out.println("execute...ok");

System.out.println("Fetching data ...");
int curRow = 0;
while (rs.next())
{
curRow++;
System.out.println("currentrow=" + curRow + " : ");

int intret = rs.getInt("int_col");
System.out.println(" int_col " + intret);

charattrUDT charattrret = (charattrUDT)rs.getObject("charattr_col");
System.out.print(" charattr_col ");
if (curRow == 2 || curRow == 6)
{
if (rs.wasNull())
System.out.println("<null>");
else
System.out.println("***ERROR: " + charattrret);
}
else
System.out.println(charattrret+"");
} //while

System.out.println("total rows expected: " + curRow);
stmt.close();

不透明类型中的智能大对象

尽管您最可能使用 GBase 8s 扩展类在不透明类型上下文之外的数据库服务器上创建大对象,但是智能大对象仍可以是不透明类型中的数据成员,

有关智能大对象的更多信息,请参阅智能大对象数据类型。

在不透明类型中大对象存储在IfxLocator 对象中;在内部定义不透明类型的 C 结构中,大对象通过 MI_LO_HANDLE 类型的定位指针引用。该对象使用IfxSmartBlob 类提供的方法创建,并且从这些方法获得的大对象句柄成为不透明类型中的数据成员。BLOB 和 CLOB 对象都使用相同的大对象句柄,如下例所示:

import java.sql.*;
import com.gbasedbt.jdbc.*;
/*
* C struct of large_bin_udt:
*
* typedef struct LARGE_BIN_TYPE
* {
* MI_LO_HANDLE lb_handle; // handle to large object (72 bytes)
* }
* large_bin_udt;
*
*/
public class largebinUDT implements SQLData
{
private String sql_type = "large_bin_udt";
public Clob lb_handle;

public largebinUDT() { }

public largebinUDT(Clob clob)
{
lb_handle = clob;
}

public String getSQLTypeName()
{
return sql_type;
}
// reads a stream of data values and builds a Java object
public void readSQL(SQLInput stream, String type) throws SQLException
{
sql_type = type;
lb_handle = stream.readClob();
}
// writes a sequence of values from a Java object to a stream
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeClob(lb_handle);
}
}

在 JDBC 应用程序中,使用 IfxSmartBlob 类提供的方法创建 MI_LO_HANDLE 对象:

String s = "insert into largebin_tab (int_col, largebin_col, lvc_col) " +
"values (?,?,?)";
System.out.println(s);
pstmt = conn.prepareStatement(s);

...
String filename = "lbin_in1.dat";
File file = new File(filename);
int fileLength = (int) file.length();
FileInputStream fin = new FileInputStream(file);

IfxLobDescriptor loDesc = new IfxLobDescriptor(conn);
System.out.println("create large object descriptor...ok");

IfxLocator loPtr = new IfxLocator();
IfxSmartBlob smb = new IfxSmartBlob((IfxConnection)conn);
int loFd = smb.IfxLoCreate(loDesc, 8, loPtr);
System.out.println("create large object...ok");

int n = smb.IfxLoWrite(loFd, fin, fileLength);
System.out.println("write file content into large object...ok");

pstmt.setInt(1, 1);
System.out.println("setInt...ok");

// initialize largebin object using the large object created
// above, before doing setObject for the large_bin_udt column.
largebinUDT largebinObj = new largebinUDT();
largebinObj.lb_handle = new IfxCblob(loPtr);
pstmt.setObject(2, largebinObj);
System.out.println("setObject(largebinUDT)...ok");

pstmt.setString(3, "Sydney");
System.out.println("setString...ok");

pstmt.executeUpdate();
System.out.println("execute...ok");

// close/release large object
smb.IfxLoClose(loFd);
System.out.println("close large object...ok");
smb.IfxLoRelease(loPtr);
System.out.println("release large object...ok");

有关详细信息,请参阅智能大对象数据类型。

使用 UDTManager 从现有的 Java 类创建不透明类型

以下示例显示应用程序如何使用 UDTManager 和 UDTMetaData 类将客户端上(数据库服务器无法访问)的现有 Java™ 类转换为数据库服务器中的 SQL 不透明类型。

使用缺省的支持函数创建不透明类型

以下示例在使用数据库服务器中现有的 Java™ 类和缺省的支持函数创建不透明类型 Circle

*/

import java.sql.*;
import com.gbasedbt.jdbc.IfmxUDTSQLInput;
import com.gbasedbt.jdbc.IfmxUDTSQLOutput;

public class Circle implements SQLData
{
private static double PI = 3.14159;

double x; // x coordinate
double y; // y coordinate
double radius;

private String type = "circle";

public String getSQLTypeName() { return type; }

public void readSQL(SQLInput stream, String typeName)
throws SQLException
{
// To be able to use the DEFAULT support functions supplied
// by the server, you must cast the stream to IfmxUDTSQLInput.
// (Server requirement)

IfmxUDTSQLInput in = (IfmxUDTSQLInput) stream;
x = in.readDouble();
y = in.readDouble();
radius = in.readDouble();
}

public void writeSQL(SQLOutput stream) throws SQLException
{
// To be able to use the DEFAULT support functions supplied
// by the server, have to cast the stream to IfmxUDTSQLOutput.
// (Server requirement)

IfmxUDTSQLOutput out = (IfmxUDTSQLOutput) stream;
out.writeDouble(x);
out.writeDouble(y);
out.writeDouble(radius);
}

public static double area(Circle c)
{
return PI * c.radius * c.radius;
}

}
不透明类型

下列 JDBC 客户端应用程序将类 Circle(在 Circle.jar 中打包)作为不透明类型安装在系统目录中。然后,应用程序可以在 SQL 语句中使用不透明类型 Circle 作为数据类型:

import java.sql.*;
import java.lang.reflect.*;


public class PlayWithCircle
{
String dbname = "test";
String url = null;
Connection conn = null;

public static void main (String args[])
{
new PlayWithCircle(args);
}

PlayWithCircle(String args[])
{
System.out.println("----------------");
System.out.println("- Start - Demo 1");
System.out.println("----------------");

// -----------
// Getting URL
// -----------
if (args.length == 0)
{
System.out.println("\n***ERROR: connection URL must be provided " +
"in order to run the demo!");
return;
}
url = args[0];

// --------------
// Loading driver
// --------------
try
{
System.out.print("Loading JDBC driver...");
Class.forName("com.gbasedbt.jdbc.Driver");
System.out.println("ok");
}
catch (java.lang.ClassNotFoundException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}

// ------------------
// Getting connection
// ------------------
try
{
System.out.print("Getting connection...");
conn = DriverManager.getConnection(url);
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("URL = '" + url + "'");
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}
System.out.println();

// -------------------
// Setup UDT meta data
// -------------------
Method areamethod = null;
try
{
Class c = Class.forName("Circle");
areamethod = c.getMethod("area", new Class[] {c});
}
catch (ClassNotFoundException e)
{
System.out.println("Cannot get Class: " + e.toString());
return;
}
catch (NoSuchMethodException e)
{
System.out.println("Cannot get Method: " + e.toString());
return;
}

UDTMetaData mdata = null;
try
{
System.out.print("Setting mdata...");
mdata = new UDTMetaData();
mdata.setSQLName("circle");
mdata.setLength(24);
mdata.setAlignment(UDTMetaData.EIGHT_BYTE);
mdata.setUDR(areamethod, "area");
mdata.setJarFileSQLName("circle_jar");
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
return;
}

// -------------------------------
// Install the UDT in the database
// -------------------------------
UDTManager udtmgr = null;
try
{
udtmgr = new UDTManager(conn);

System.out.println("\ncreateJar()");
String jarfilename = udtmgr.createJar(mdata,
new String[] {"Circle.class"}); // jarfilename = circle.jar
System.out.println(" jarfilename = " + jarfilename);

System.out.println("\nsetJarTmpPath()");
udtmgr.setJarTmpPath("/tmp");

System.out.print("\ncreateUDT()...");
udtmgr.createUDT(mdata,
"/vobs/jdbc/demo/tools/udtudrmgr/" + jarfilename, "Circle", 0);
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
return;
}
System.out.println();

// ---------------
// Now use the UDT
// ---------------
try
{
String s = "drop table tab";
System.out.print(s + "...");
Statement stmt = conn.createStatement();
int count = stmt.executeUpdate(s);
stmt.close();
System.out.println("ok");
}
catch ( SQLException e)
{
// -206 The specified table (%s) is not in the database.
if (e.getErrorCode() != -206)
{
System.out.println("\n***ERROR: " + e.getMessage());
return;
}
System.out.println("ok");
}

executeUpdate("create table tab (c circle)");

// test DEFAULT Input function
executeUpdate("insert into tab values ('10 10 10')");

// test DEFAULT Output function
try
{
String s = "select c::lvarchar from tab";
System.out.println(s);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(s);
if (rs.next())
{
String c = rs.getString(1);
System.out.println(" circle = '" + c + "'");
}
rs.close();
stmt.close();
}
catch (SQLException e)
{
System.out.println("***ERROR: " + e.getMessage());
}
System.out.println();

// test DEFAULT Send function
try
{
// setup type map before using getObject() for UDT data.
java.util.Map customtypemap = conn.getTypeMap();
System.out.println("getTypeMap...ok");
if (customtypemap == null)
{
System.out.println("***ERROR: map is null!");
return;
}
customtypemap.put("circle", Class.forName("Circle"));
System.out.println("put...ok");

String s = "select c from tab";
System.out.println(s);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(s);
if (rs.next())
{
Circle c = (Circle)rs.getObject(1, customtypemap);
System.out.println(" c.x = " + c.x);
System.out.println(" c.y = " + c.y);
System.out.println(" c.radius = " + c.radius);
}
rs.close();
stmt.close();
}
catch (SQLException e)
{
System.out.println("***ERROR: " + e.getMessage());
}
catch (ClassNotFoundException e)
{
System.out.println("***ERROR: " + e.getMessage());
}
System.out.println();

// test user's non-support UDR
try
{
String s = "select area(c) from tab";
System.out.println(s);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(s);
if (rs.next())
{
double a = rs.getDouble(1);
System.out.println(" area = " + a);
}
rs.close();
stmt.close();
}
catch (SQLException e)
{
System.out.println("***ERROR: " + e.getMessage());
}
System.out.println();

executeUpdate("drop table tab");

// ------------------
// Closing connection
// ------------------
try
{
System.out.print("Closing connection...");
conn.close();
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
}
}

使用您提供的支持函数创建不透明类型

在此示例中,客户端上的 Java™ 类 Circle2 被映射到一个名为circle2 的 SQL 不透明类型。circle2 不透明类型使用程序员提供的支持函数:

import java.text.*;
import com.gbasedbt.jdbc.IfmxUDTSQLInput;
import com.gbasedbt.jdbc.IfmxUDTSQLOutput;

public class Circle2 implements SQLData
{
private static double PI = 3.14159;

double x; // x coordinate
double y; // y coordinate
double radius;

private String type = "circle2";

public String getSQLTypeName() { return type; }

public void readSQL(SQLInput stream, String typeName)
throws SQLException
{
/* commented out - because the first release of the UDT/UDR Manager feature
* does not support mixing user-supplied support functions
* with server DEFAULT support functions.
* However, once the mix is supported, this code needs to be used to
* replace the existing code.
*
// To be able to use the DEFAULT support functions (other than
// Input/Output) supplied by the server, you must cast the stream
// to IfmxUDTSQLInput.

IfmxUDTSQLInput in = (IfmxUDTSQLInput) stream;
x = in.readDouble();
y = in.readDouble();
radius = in.readDouble();
*/

x = stream.readDouble();
y = stream.readDouble();
radius = stream.readDouble();
}

public void writeSQL(SQLOutput stream) throws SQLException
{
/* commented out - because the 1st release of UDT/UDR Manager feature
* doesn't support the mixing of user support functions
* with server DEFAULT support functions.
* However, once the mix is supported, this code needs to be used to
* replace the existing code.
*
// To be able to use the DEFAULT support functions (other than
// Input/Output) supplied by the server, you must cast the stream
// to IfmxUDTSQLOutput.

IfmxUDTSQLOutput out = (IfmxUDTSQLOutput) stream;
out.writeDouble(x);
out.writeDouble(y);
out.writeDouble(radius);
*/

stream.writeDouble(x);
stream.writeDouble(y);
stream.writeDouble(radius);
}

/**
* Input function - return the object from the String representation -
* 'x y radius'.
*/
public static Circle2 fromString(String text)
{
Number a = null;
Number b = null;
Number r = null;

try
{
ParsePosition ps = new ParsePosition(0);
a = NumberFormat.getInstance().parse(text, ps);
ps.setIndex(ps.getIndex() + 1);
b = NumberFormat.getInstance().parse(text, ps);
ps.setIndex(ps.getIndex() + 1);
r = NumberFormat.getInstance().parse(text, ps);
}
catch (Exception e)
{
System.out.println("In exception : " + e.getMessage());
}

Circle2 c = new Circle2();
c.x = a.doubleValue();
c.y = b.doubleValue();
c.radius = r.doubleValue();

return c;
}

/**
* Output function - return the string of the form 'x y radius'.
*/
public static String makeString(Circle2 c)
{
StringBuffer sbuff = new StringBuffer();
FieldPosition fp = new FieldPosition(NumberFormat.INTEGER_FIELD);
NumberFormat.getInstance().format(c.x, sbuff, fp);
sbuff.append(" ");
NumberFormat.getInstance().format(c.y, sbuff, fp);
sbuff.append(" ");
NumberFormat.getInstance().format(c.radius, sbuff, fp);

return sbuff.toString();
}

/**
* user function - get the area of a circle.
*/
public static double area(Circle2 c)
{
return PI * c.radius * c.radius;
}

}
不透明类型

下列 JDBC 客户端应用程序将类 Circle2(在 Circle2.jar 中打包)作为不透明类型安装在系统目录中。然后,应用程序可以在 SQL 语句中使用不透明类型 Circle2 作为数据类型:

import java.sql.*;
import java.lang.reflect.*;


public class PlayWithCircle2
{
String dbname = "test";
String url = null;
Connection conn = null;

public static void main (String args[])
{
new PlayWithCircle2(args);
}

PlayWithCircle2(String args[])
{

// -----------
// Getting URL
// -----------
if (args.length == 0)
{
System.out.println("\n***ERROR: connection URL must be provided " +
"in order to run the demo!");
return;
}
url = args[0];
// --------------
// Loading driver
// --------------
try
{
System.out.print("Loading JDBC driver...");
Class.forName("com.gbasedbt.jdbc.Driver");
}
catch (java.lang.ClassNotFoundException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}
try
{
conn = DriverManager.getConnection(url);
}
catch (SQLException e)
{
System.out.println("URL = '" + url + "'");
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}
System.out.println();

不需现有的 Java 类创建不透明类型

在此示例中,使用客户端上的 Java™ 类MyCircle 在数据库服务器中创建一个名为 ACircle的固定长度的不透明类型。ACircle 不透明类型使用数据库服务器提供的缺省支持函数:

import java.sql.*;

public class MyCircle
{
String dbname = "test";
String url = null;
Connection conn = null;

public static void main (String args[])
{
new MyCircle(args);
}

MyCircle(String args[])
{
System.out.println("----------------");
System.out.println("- Start - Demo 3");
System.out.println("----------------");

// -----------
// Getting URL
// -----------
if (args.length == 0)
{
System.out.println("\n***ERROR: connection URL must be provided " +
"in order to run the demo!");
return;
}
url = args[0];

// --------------
// Loading driver
// --------------
try
{
System.out.print("Loading JDBC driver...");
Class.forName("com.gbasedbt.jdbc.Driver");
System.out.println("ok");
}
catch (java.lang.ClassNotFoundException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}

// ------------------
// Getting connection
// ------------------
try
{
System.out.print("Getting connection...");
conn = DriverManager.getConnection(url);
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("URL = '" + url + "'");
System.out.println("\n***ERROR: " + e.getMessage());
e.printStackTrace();
return;
}
// -------------------
// Setup UDT meta data
// -------------------
UDTMetaData mdata = null;
try
{
mdata = new UDTMetaData();
System.out.print("Setting fields in mdata...");
mdata.setSQLName("acircle");
mdata.setLength(24);
mdata.setFieldCount(3);
mdata.setFieldName(1, "x");
mdata.setFieldName(2, "y");
mdata.setFieldName(3, "radius");
mdata.setFieldType(1, com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT);
mdata.setFieldType(2, com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT);
mdata.setFieldType(3, com.gbasedbt.lang.IfxTypes.IFX_TYPE_INT);
// set class name if don't want to use the default name
// <udtsqlname>.class
mdata.setClassName("ACircle");
mdata.setJarFileSQLName("ACircleJar");
mdata.keepJavaFile(true);
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("***ERROR: " + e.getMessage());
return;
}

// --------------------------------------------------------
// create java file for UDT and install UDT in the database
// --------------------------------------------------------
UDTManager udtmgr = null;
try
{
udtmgr = new UDTManager(conn);

System.out.println("Creating .class/.java files - " +
"createUDTClass()");
String classname = udtmgr.createUDTClass(mdata); // generated
//java file is kept
System.out.println(" classname = " + classname);

System.out.println("\nCreating .jar file - createJar()");
String jarfilename = udtmgr.createJar(mdata,
new String[]{"ACircle.class"}); // jarfilename is
// <udtsqlname>.jar
// ie. acircle.jar

System.out.println("\nsetJarTmpPath()");
udtmgr.setJarTmpPath("/tmp");

System.out.print("\ncreateUDT()...");
udtmgr.createUDT(mdata,
"/vobs/jdbc/demo/tools/udtudrmgr/" + jarfilename, "ACircle", 0);
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
return;
}
System.out.println();


// ---------------
// Now use the UDT
// ---------------
try
{
String s = "drop table tab";
System.out.print(s + "...");
Statement stmt = conn.createStatement();
int count = stmt.executeUpdate(s);
stmt.close();
System.out.println("ok");
}
catch ( SQLException e)
{
// -206 The specified table (%s) is not in the database.
if (e.getErrorCode() != -206)
{
System.out.println("\n***ERROR: " + e.getMessage());
return;
}
System.out.println("ok");
}

executeUpdate("create table tab (c acircle)");

// test DEFAULT Input function
executeUpdate("insert into tab values ('10 10 10')");

// test DEFAULT Output function
try
{
String s = "select c::lvarchar from tab";
System.out.println(s);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(s);
if (rs.next())
{
String c = rs.getString(1);
System.out.println(" acircle = '" + c + "'");
}
rs.close();
stmt.close();
}
catch (SQLException e)
{
System.out.println("***ERROR: " + e.getMessage());
}
System.out.println();

executeUpdate("drop table tab");

// ------------------
// Closing connection
// ------------------
try
{
System.out.print("Closing connection...");
conn.close();
System.out.println("ok");
}
catch (SQLException e)
{
System.out.println("\n***ERROR: " + e.getMessage());
}

System.out.println("------------------");
System.out.println("- End - UDT Demo 3");
System.out.println("------------------");

}

使用 UDRManager 创建 UDR

以下代码显示应用程序如何使用 UDRManager和 UDRMetaData类将客户端上的 Java™ 类(数据库服务器无法访问)转换为数据库服务器中的 Java UDR。之后,应用程序可以在 SQL 语句中引用此 UDR 。在此示例中,客户端上的 Java 类被命名为 Group1。该类具有两个例程 udr1 和udr2

下列代码创建 Group1 类中的方法以在数据库服务器中注册为 UDR:

import java.sql.*;

public class Group1
{
public static String udr1 (String s1, String s2)
throws SQLException
{
return s1 + s2;
}
// Return a formatted string with all inputs
public static String udr2 (Integer i, String s1,
String s2) throws SQLException
{
return "{" + i + "," + s1 + "," + s2 +"}";
}
}

以下代码将数据库服务器中 Java 方法 udr1 和 udr2 创建为 UDR group1_udr1 和 group1_udr2,然后使用 UDR:

import java.sql.*;
import java.lang.reflect.*;

public class PlayWithGroup1
{
// Open a connection...
url = "jdbc:gbasedbt-sqli://hostname:portnum:db/:
gbasedbtserver=servname;user=scott;password=tiger;
myConn = DriverManager.getConnection(url);

//Install the routines in the database.
UDRManager udtmgr = new UDRManager(myConn);
UDRMetaData mdata = new UDRMetaData();
Class gp1 = Class.forName("Group1");
Method method1 = gp1.getMethod("udr1",
new Class[]{String.class, String.class});
Method method2 = gp1.getMethod("udr2",
new Class[]{Integer.class, String.class, String.class});
mdata.setUDR(method1, "group1_udr1");
mdata.setUDR(method2, "group1_udr2");
mdata.setJarFileSQLName("group1_jar");
udtmgr.createUDRs(mdata, "Group1.jar", "Group1", 0);

// Use the UDRs in SQL statements:
Statement stmt = myConn.createStatement();
stmt.executeUpdate("create table tab (c1 varchar(10),
c2 char(20)", c3 int);
stmt.close();
Statement stmt = myConn.createStatement();
stmt.executeUpdate("insert into tab values ('hello', 'world',
222)");
stmt.close();

Statement stmt = myConn.createStatement();
ResultSet r = stmt.executeQuery("select c3, group1_udr2(c3, c1, c2)
from tab where group1_udr1(c1, c2) = 'hello world'");

...
}